package tianrun.ziguan.api.calculate.config.service.sync.handler.asset;

import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import tianrun.ziguan.api.calculate.config.dto.request.AssetEdgeInputInstanceVO;
import tianrun.ziguan.api.calculate.config.dto.request.AssetStaticPropertiesInstanceVO;
import tianrun.ziguan.api.calculate.config.entity.*;
import tianrun.ziguan.api.calculate.config.enums.MoldEnum;
import tianrun.ziguan.api.calculate.config.service.asset.instance.ITAssetStaticPropertiesInstanceService;
import tianrun.ziguan.api.calculate.config.service.asset.module.ITAssetStaticPropertiesModuleService;
import tianrun.ziguan.api.calculate.config.service.cal.asset.ITCalAssetService;
import tianrun.ziguan.api.calculate.config.service.sync.SyncType;
import tianrun.ziguan.api.calculate.config.service.sync.handler.AbstractSyncHandler;
import tianrun.ziguan.api.calculate.config.service.sync.handler.SyncHandler;
import tianrun.ziguan.api.calculate.config.service.template.instance.ITStaticPropertiesInstanceService;
import tianrun.ziguan.api.calculate.config.service.template.module.ITStaticPropertiesModuleService;
import tianrun.ziguan.api.calculate.config.utils.CollectionUtil;
import tianrun.ziguan.api.calculate.config.utils.MyBeanUtil;
import tianrun.ziguan.api.calculate.config.utils.Setter;
import tianrun.ziguan.api.common.util.ListUtil;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Service
public class AssetStaticPropertiesModuleHandler extends AbstractSyncHandler {
    private final ITCalAssetService calAssetService;
    private final ITStaticPropertiesModuleService staticPropertiesModuleService;
    private final ITAssetStaticPropertiesModuleService assetStaticPropertiesModuleService;
    private final ITStaticPropertiesInstanceService staticPropertiesInstanceService;
    private final ITAssetStaticPropertiesInstanceService assetStaticPropertiesInstanceService;

    public AssetStaticPropertiesModuleHandler(ITCalAssetService calAssetService, ITStaticPropertiesModuleService staticPropertiesModuleService, ITAssetStaticPropertiesModuleService assetStaticPropertiesModuleService, ITStaticPropertiesInstanceService staticPropertiesInstanceService, ITAssetStaticPropertiesInstanceService assetStaticPropertiesInstanceService) {
        this.calAssetService = calAssetService;
        this.staticPropertiesModuleService = staticPropertiesModuleService;
        this.assetStaticPropertiesModuleService = assetStaticPropertiesModuleService;
        this.staticPropertiesInstanceService = staticPropertiesInstanceService;
        this.assetStaticPropertiesInstanceService = assetStaticPropertiesInstanceService;
    }

    @Override
    public MoldEnum mold() {
        return MoldEnum.StaticProperty;
    }

    @Override
    public SyncType type() {
        return SyncType.ASSET;
    }

    /**
     * @param moduleIds 同一模板下不同组件的id
     * @param parentIds t_template.id or t_cal_asset.id
     */
    @Override
    public void handler(Set<Long> moduleIds, Set<Long> parentIds) {
        Map<TAssetStaticPropertiesModule, List<TAssetStaticPropertiesInstance>> map = new HashMap<>();
        List<TCalAsset> calAssets = calAssetService.getByIds(parentIds);
        //1获取模板下的所有组件和实例
        List<TStaticPropertiesModule> sourceModules = staticPropertiesModuleService.getByIds(moduleIds);
        List<TStaticPropertiesInstance> sourceInstances = staticPropertiesInstanceService.listByModuleIds(moduleIds);

        Map<TStaticPropertiesModule, List<TStaticPropertiesInstance>> sourceMap = sourceModules.stream().collect(Collectors.toMap(Function.identity(), module -> sourceInstances.stream().filter(i -> Objects.equals(i.getModuleId(), module.getId())).collect(Collectors.toList())));

        //2获取对应的资产下的组件和实例
        List<TAssetStaticPropertiesModule> staticPropertiesModules = assetStaticPropertiesModuleService.getByCalAssetIds(parentIds);
        List<AssetStaticPropertiesInstanceVO> assetStaticPropertiesInstanceVOS = assetStaticPropertiesInstanceService.listVOByCalAssetIds(parentIds);
        Map<Long, List<AssetStaticPropertiesInstanceVO>> targetInstancesMap = ListUtil.groupList(assetStaticPropertiesInstanceVOS, AssetStaticPropertiesInstanceVO::getCalAssetId);
        Map<Long, List<TAssetStaticPropertiesModule>> targetMap = new HashMap<>();
        //初始化
        calAssets.forEach(asset -> targetMap.put(asset.getId(), Lists.newArrayList()));
        targetMap.putAll(ListUtil.groupList(staticPropertiesModules, TAssetStaticPropertiesModule::getCalAssetId));


        //对比-组件和实例的关联字段
        targetMap.forEach((assetId, targetModules) -> {
            sourceMap.forEach((sourceModule, sourceInstanceList) -> {
                Optional<TAssetStaticPropertiesModule> first = targetModules.stream().filter(m -> Objects.equals(m.getTemplateModuleId(), sourceModule.getId())).findFirst();
                TAssetStaticPropertiesModule newTargetModule = first.orElseGet(TAssetStaticPropertiesModule::new);
                MyBeanUtil.doCopy(sourceModule, newTargetModule,
                        Setter.set(newTargetModule::setId, newTargetModule.getId()),
                        Setter.set(newTargetModule::setCalAssetId, assetId),
                        Setter.set(newTargetModule::setTemplateModuleId, sourceModule.getId()));
                List<TAssetStaticPropertiesInstance> collect = targetInstancesMap.getOrDefault(assetId, Lists.newArrayList()).stream().map(a -> (TAssetStaticPropertiesInstance) a).collect(Collectors.toList());
                map.put(newTargetModule, getNewTargetInstances(collect, sourceInstanceList, newTargetModule, TAssetStaticPropertiesInstance.class));
            });
        });
        //修改数据
        if (map.isEmpty()) return;
        assetStaticPropertiesModuleService.saveOrUpdateBatch(map.keySet());
        map.forEach((module, instances) -> instances.forEach(instance -> instance.setModuleId(module.getId())));
        List<TAssetStaticPropertiesInstance> saveInstances = map.values().stream().flatMap(Collection::stream).collect(Collectors.toList());
        if (saveInstances.isEmpty()) return;
        assetStaticPropertiesInstanceService.saveOrUpdateBatch(saveInstances);

        //删除组件内不等于-1的实例数据
        List<Long> instanceIds = saveInstances.stream().map(TAssetStaticPropertiesInstance::getId).collect(Collectors.toList());
        assetStaticPropertiesInstanceService.remove(Wrappers.
                <TAssetStaticPropertiesInstance>lambdaQuery().
                in(TAssetStaticPropertiesInstance::getModuleId, map.keySet().stream().map(TAssetStaticPropertiesModule::getId).collect(Collectors.toList())).
                ne(TAssetStaticPropertiesInstance::getTemplateInstanceId, -1).
                notIn(TAssetStaticPropertiesInstance::getId, instanceIds)
        );
    }


    public void handler1(Set<Long> moduleIds, Set<Long> parentIds) {
        Map<Long, Map<Long, TAssetStaticPropertiesModule>> modules = getModules(moduleIds, parentIds);
        Collection<TStaticPropertiesInstance> sources = staticPropertiesInstanceService.listByModuleIds(moduleIds);
        Collection<AssetStaticPropertiesInstanceVO> targets = assetStaticPropertiesInstanceService.listVOByCalAssetIds(parentIds);
        Map<Long, List<AssetStaticPropertiesInstanceVO>> templateMapping = targets.stream().collect(Collectors.groupingBy(AssetStaticPropertiesInstanceVO::getCalAssetId));

        List<TAssetStaticPropertiesInstance> list = Lists.newArrayList();
        List<Long> delIds = Lists.newArrayList();
        for (TStaticPropertiesInstance source : sources) {
            String key = source.getLabel();
            Map<Long, TAssetStaticPropertiesModule> moduleMap = modules.get(source.getModuleId());
            moduleMap.forEach((parentId, module) -> {
                List<AssetStaticPropertiesInstanceVO> values = templateMapping.getOrDefault(parentId, Collections.emptyList());
                List<Long> ids = values.stream().filter(i -> Objects.equals(i.getLabel(), key)).map(AssetStaticPropertiesInstanceVO::getId).collect(Collectors.toList());
                delIds.addAll(ids);
                TAssetStaticPropertiesInstance target = new TAssetStaticPropertiesInstance();
                list.add(MyBeanUtil.doCopy(source, target, new Setter<>(target::setId, null), new Setter<>(target::setModuleId, module.getId())));
            });
        }
        if (!list.isEmpty()) {
            assetStaticPropertiesInstanceService.saveOrUpdateBatch(list);
        }
        if (delIds.isEmpty()) {
            return;
        }
        assetStaticPropertiesInstanceService.removeByIds(delIds);
    }

    private Map<Long, Map<Long, TAssetStaticPropertiesModule>> getModules(Set<Long> moduleIds, Set<Long> parentIds) {
        Collection<TCalAsset> calAssets = calAssetService.listByIds(parentIds);
        Map<Long, TCalAsset> calAssetMap = CollectionUtil.toMap(calAssets, TCalAsset::getId);
        Map<Long, Map<Long, TAssetStaticPropertiesModule>> map = Maps.newHashMap();
        List<TAssetStaticPropertiesModule> list = Lists.newArrayList();
        for (Long moduleId : moduleIds) {
            // todo error
            TStaticPropertiesModule module = staticPropertiesModuleService.getById(moduleId);
            module.setId(null);
            Map<Long, TAssetStaticPropertiesModule> map1 = Maps.newHashMap();
            for (Long parentId : parentIds) {
                TCalAsset calAsset = calAssetMap.get(parentId);
                if (calAsset == null) {
                    continue;
                }
                TAssetStaticPropertiesModule module1 = new TAssetStaticPropertiesModule();
                BeanUtils.copyProperties(module, module1);
                module1.setName(module.getName() + StringPool.UNDERSCORE + System.currentTimeMillis());
                module1.setCalAssetId(parentId);
                map1.put(parentId, module1);
                list.add(module1);
            }
            map.put(moduleId, map1);
        }
        assetStaticPropertiesModuleService.saveBatch(list);
        return map;
    }
}
